package com.example.study.page.view

import android.content.Context
import android.util.AttributeSet
import android.view.ViewGroup

/**
 * Created by lijinxi on 2024/2/27
 * @Description:
 */
class FlowLayout(context: Context, attrs: AttributeSet? = null) : ViewGroup(context, attrs) {
    // onLayout 方法负责摆放子视图。
    // 参数 l, t, r, b 是 ViewGroup 的左上角和右下角的坐标。
    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        var left = paddingLeft
        var top = paddingTop
        var lineHeight = 0

        // 为每个子视图设置位置和尺寸
        // 当一行的宽度不足以容纳子视图时，换行并更新行的累计高度。
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            if (left + child.measuredWidth > r - l) {
                //换行
                left = paddingLeft
                top += lineHeight
                lineHeight = 0
            }
            // 设置子视图的位置和尺寸
            child.layout(left, top, left + child.measuredWidth, top + child.measuredHeight)

            left += child.measuredWidth
            lineHeight = maxOf(lineHeight, child.measuredHeight)
        }
    }

    // onMeasure 方法用于计算 ViewGroup 以及其所有子视图的大小
    // widthMeasureSpec 和 heightMeasureSpec 参数包含了父视图为当前视图推荐的尺寸和模式。
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        // 获取测量规格中的宽度和高度值。
        val sizeWidth = MeasureSpec.getSize(widthMeasureSpec)
        val sizeHeight = MeasureSpec.getSize(heightMeasureSpec)
        val modeWidth = MeasureSpec.getMode(widthMeasureSpec)
        val modeHeight = MeasureSpec.getMode(heightMeasureSpec)

        for (i in 0 until childCount) {
            val child = getChildAt(i)
            val lp = child.layoutParams

            // 为子视图生成对应的测量规格。
            val childWidthMeasureSpec =
                getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight, lp.width)
            val childHeightMeasureSpec =
                getChildMeasureSpec(heightMeasureSpec, paddingLeft + paddingRight, lp.height)

            // 测量子视图。
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec)
        }

        var width = 0
        var height = paddingTop + paddingBottom
        var lineWidth = paddingLeft + paddingRight
        var lineHeight = 0

        // 计算子视图位置以及布局的最终宽度和高度。
        for (i in 0 until childCount) {
            val child = getChildAt(i)

            // 检查行宽是否超出了当前行的最大宽度。
            // 如果超出，则换行，重置行宽，并将当前子视图高度累加到总高度。
            if (lineWidth + child.measuredWidth > sizeWidth) {
                // 换行
                lineWidth = paddingLeft + paddingRight + child.measuredWidth
                height += lineHeight
                lineHeight = child.measuredHeight
            } else {
                lineWidth += child.measuredWidth
                lineHeight = maxOf(lineHeight, child.measuredHeight)
            }

            // 更新布局宽度为最大行宽。
            width = maxOf(width, lineWidth)

            // 最后一个子视图，把最后一行的高度加入总高度。
            if (i == childCount - 1) {
                height += lineHeight
            }
        }

        setMeasuredDimension(
            if (modeWidth == MeasureSpec.EXACTLY) sizeWidth else width,
            if (modeHeight == MeasureSpec.EXACTLY) sizeHeight else height
        )
    }
}